/** @file
  Definitions for on-disk FAT structures.

Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials are licensed and made available
under the terms and conditions of the BSD License which accompanies this
distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.


**/

#ifndef _FATFILESYSTEM_H_
#define _FATFILESYSTEM_H_

#pragma pack(1)
//
// FAT info signature
//
#define FAT_INFO_SIGNATURE        0x41615252
#define FAT_INFO_BEGIN_SIGNATURE  0x61417272
#define FAT_INFO_END_SIGNATURE    0xAA550000
//
// FAT entry values
//
#define FAT_CLUSTER_SPECIAL_EXT       (MAX_UINTN & (~0xF))
#define FAT_CLUSTER_SPECIAL           ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)
#define FAT_CLUSTER_FREE              0
#define FAT_CLUSTER_RESERVED          (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_BAD               (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_LAST              (-1)
#define FAT_END_OF_FAT_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))
#define FAT_MIN_CLUSTER               2
#define FAT_MAX_FAT12_CLUSTER         0xFF5
#define FAT_MAX_FAT16_CLUSTER         0xFFF5
#define FAT_CLUSTER_SPECIAL_FAT12     0xFF7
#define FAT_CLUSTER_SPECIAL_FAT16     0xFFF7
#define FAT_CLUSTER_SPECIAL_FAT32     0x0FFFFFF7
#define FAT_CLUSTER_MASK_FAT12        0xFFF
#define FAT_CLUSTER_UNMASK_FAT12      0xF000
#define FAT_CLUSTER_MASK_FAT32        0x0FFFFFFF
#define FAT_CLUSTER_UNMASK_FAT32      0xF0000000
#define FAT_POS_FAT12(a)              ((a) * 3 / 2)
#define FAT_POS_FAT16(a)              ((a) * 2)
#define FAT_POS_FAT32(a)              ((a) * 4)
#define FAT_ODD_CLUSTER_FAT12(a)      (((a) & 1) != 0)


//
// FAT attribute define
//
#define FAT_ATTRIBUTE_READ_ONLY 0x01
#define FAT_ATTRIBUTE_HIDDEN    0x02
#define FAT_ATTRIBUTE_SYSTEM    0x04
#define FAT_ATTRIBUTE_VOLUME_ID 0x08
#define FAT_ATTRIBUTE_DIRECTORY 0x10
#define FAT_ATTRIBUTE_ARCHIVE   0x20
#define FAT_ATTRIBUTE_DEVICE    0x40
#define FAT_ATTRIBUTE_LFN       0x0F
//
// Some Long File Name definitions
//
#define FAT_LFN_LAST            0x40  // Ordinal field
#define MAX_LFN_ENTRIES         20
#define LFN_CHAR1_LEN           5
#define LFN_CHAR2_LEN           6
#define LFN_CHAR3_LEN           2
#define LFN_CHAR_TOTAL          (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)
#define LFN_ENTRY_NUMBER(a)     (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)
//
// Some 8.3 File Name definitions
//
#define FAT_MAIN_NAME_LEN       8
#define FAT_EXTEND_NAME_LEN     3
#define FAT_NAME_LEN            (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)
//
// Some directory entry information
//
#define FAT_ENTRY_INFO_OFFSET   13
#define DELETE_ENTRY_MARK       0xE5
#define EMPTY_ENTRY_MARK        0x00

//
// Volume dirty Mask
//
#define FAT16_DIRTY_MASK        0x7fff
#define FAT32_DIRTY_MASK        0xf7ffffff
//
// internal flag
//
#define FAT_CASE_MIXED          0x01
#define FAT_CASE_NAME_LOWER     0x08
#define FAT_CASE_EXT_LOWER      0x10

typedef struct {
  UINT8   Ia32Jump[3];
  CHAR8   OemId[8];
  UINT16  SectorSize;
  UINT8   SectorsPerCluster;
  UINT16  ReservedSectors;
  UINT8   NumFats;
  UINT16  RootEntries;          // < FAT32, root dir is fixed size
  UINT16  Sectors;
  UINT8   Media;
  UINT16  SectorsPerFat;        // < FAT32
  UINT16  SectorsPerTrack;      // (ignored)
  UINT16  Heads;                // (ignored)
  UINT32  HiddenSectors;        // (ignored)
  UINT32  LargeSectors;         // Used if Sectors==0
} FAT_BOOT_SECTOR_BASIC;

typedef struct {
  UINT8 PhysicalDriveNumber;    // (ignored)
  UINT8 CurrentHead;            // holds boot_sector_dirty bit
  UINT8 Signature;              // (ignored)
  CHAR8 Id[4];
  CHAR8 FatLabel[11];
  CHAR8 SystemId[8];
} FAT_BOOT_SECTOR_EXT;

typedef struct {
  UINT32  LargeSectorsPerFat;   // FAT32
  UINT16  ExtendedFlags;        // FAT32 (ignored)
  UINT16  FsVersion;            // FAT32 (ignored)
  UINT32  RootDirFirstCluster;  // FAT32
  UINT16  FsInfoSector;         // FAT32
  UINT16  BackupBootSector;     // FAT32
  UINT8   Reserved[12];         // FAT32 (ignored)
  UINT8   PhysicalDriveNumber;  // (ignored)
  UINT8   CurrentHead;          // holds boot_sector_dirty bit
  UINT8   Signature;            // (ignored)
  CHAR8   Id[4];
  CHAR8   FatLabel[11];
  CHAR8   SystemId[8];
} FAT32_BOOT_SECTOR_EXT;

typedef union {
    FAT_BOOT_SECTOR_EXT   FatBse;
    FAT32_BOOT_SECTOR_EXT Fat32Bse;
  } FAT_BSE;

typedef struct {
  FAT_BOOT_SECTOR_BASIC   FatBsb;
  FAT_BSE  FatBse;
} FAT_BOOT_SECTOR;

//
// FAT Info Structure
//
typedef struct {
  UINT32  ClusterCount;
  UINT32  NextCluster;
} FAT_FREE_INFO;

typedef struct {
  UINT32        Signature;
  UINT8         ExtraBootCode[480];
  UINT32        InfoBeginSignature;
  FAT_FREE_INFO FreeInfo;
  UINT8         Reserved[12];
  UINT32        InfoEndSignature;
} FAT_INFO_SECTOR;

//
// Directory Entry
//
#define FAT_MAX_YEAR_FROM_1980  0x7f
typedef struct {
  UINT16  Day : 5;
  UINT16  Month : 4;
  UINT16  Year : 7;                 // From 1980
} FAT_DATE;

typedef struct {
  UINT16  DoubleSecond : 5;
  UINT16  Minute : 6;
  UINT16  Hour : 5;
} FAT_TIME;

typedef struct {
  FAT_TIME  Time;
  FAT_DATE  Date;
} FAT_DATE_TIME;

typedef struct {
  CHAR8         FileName[11];       // 8.3 filename
  UINT8         Attributes;
  UINT8         CaseFlag;
  UINT8         CreateMillisecond;  // (creation milliseconds - ignored)
  FAT_DATE_TIME FileCreateTime;
  FAT_DATE      FileLastAccess;
  UINT16        FileClusterHigh;    // >= FAT32
  FAT_DATE_TIME FileModificationTime;
  UINT16        FileCluster;
  UINT32        FileSize;
} FAT_DIRECTORY_ENTRY;

typedef struct {
  UINT8   Ordinal;
  CHAR8   Name1[10];                // (Really 5 chars, but not WCHAR aligned)
  UINT8   Attributes;
  UINT8   Type;
  UINT8   Checksum;
  CHAR16  Name2[6];
  UINT16  MustBeZero;
  CHAR16  Name3[2];
} FAT_DIRECTORY_LFN;

#pragma pack()

#endif
